#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <time.h>
#include "dominion.h"

/**
 * Sets up the initial gameState struct with all required variables
 * @param gameState - takes in a reference to a gameState which will be modified
 */
void initGame(struct gameState *game)
{
  int *k = malloc(sizeof(int) * 10);
  int seed = rand() % (INT_MAX - 1) + 1; // any random number above 1
  k = kingdomCards(0,1,2,3,4,5,6,7,8,9); // kindom cards required, if these values change, most of the tests fail
  initializeGame(2, k, seed, game); // must have an initialized game state

  return;
}

void stateDump(struct gameState *game, int playerTurn)
{
  printf("handCount - %d\n", game->handCount[playerTurn]);
  printf("deckCount - %d\n", game->deckCount[playerTurn]);
  printf("discardCount - %d\n", game->discardCount[playerTurn]);
  printf("playedCardCount - %d\n", game->playedCardCount);
}

/**
 * displays whether the test failed or passed
 * @param  string   a char array (string) with the value being tested
 * @param  expected expected result of the test
 * @param  result   actual result of the test
 */
int check(char *string, int expected, int result, struct gameState *game)
{
  if (expected != result)
  {
    printf("FAIL - %s: expected - %d, result - %d\n", string, expected, result);
    return -1; // return an error
  }

  return 0; // successful
}

int testCase(struct gameState *game)
{
  int playerTurn = 0;
  int failed = 0;
  int numCards = 0; 
  int treasure = 0;
  int beforeHand = 0;
  int afterHand = 0;
  int beforeDeck = 0;
  int afterDeck = 0;
  int expectedDeckSize = 0;
  int indexA = 0;
  int indexB = 0;
  for (int j = 0; j < 100; ++j) // run 100 hundred test cases
  {
    int deckSize = rand() % 60 + 30; // between 30 and 90
    failed = 0;
    numCards = 0; 
    treasure = 0;
    for (int i = 0; i < deckSize; ++i) // assign 50 cards
    {
      game->deck[playerTurn][i] = rand() % 27; // assign a random number
    }
    game->deckCount[playerTurn] = deckSize - 1;
    /* assigns two random indices which will contain two random treasure cards, ensuring that the deck does not need a reshuffle */
    while (indexA != indexB && !(indexA < 5 || indexB < 5))
    {
      indexA = rand() % deckSize + 1;
      indexB = rand() % deckSize + 1;
    }
    /* set the two indices with random treasure cards */
    game->deck[playerTurn][indexA] = rand() % 3 + 4; // fill 4,5,6
    game->deck[playerTurn][indexB] = rand() % 3 + 4; // fill 4,5,6
    /* sizes before we make changes */
    beforeHand = game->handCount[playerTurn];
    beforeDeck = game->deckCount[playerTurn];
    /* start at 5, the size of the hand */
    int i = 5;
    /* count the number of cards we pass until we get to 2 treasure */
    while (treasure < 2)
    {
      /* only coun copper, silver, gold cards */
      if (game->deck[playerTurn][i] == copper || game->deck[playerTurn][i] == silver || game->deck[playerTurn][i] == gold)
        treasure++;
      numCards++;
      i++;
    }
    expectedDeckSize = beforeDeck - numCards;
    drawAdventurerCard(playerTurn, game);
    afterHand = game->handCount[playerTurn];
    afterDeck = game->deckCount[playerTurn];
    /* run the unit tests for each random set */
    if (check("Before handCount", (5 + (j * 2)), beforeHand, game) == -1)
      failed = 1;
    if (check("After handCount", (7 + (j * 2)), afterHand, game) == -1)
      failed = 1;
    if (check("Before deckCount", (deckSize - 1), beforeDeck, game) == -1)
      failed = 1;
    if (check("After afterCount", ((deckSize - 1) - numCards), afterDeck, game) == -1)
      failed = 1;
    if (failed == 1)
      stateDump(game, playerTurn);
      printf("numCards - %d\n", numCards);
      printf("deckSize - %d\n", deckSize);
  }
}

int main(int argc, char const *argv[])
{
  struct gameState *game = malloc(sizeof(struct gameState));

  srand(time(NULL)); // seed the random number generator with the current time
  initGame(game);
  testCase(game);
  free(game); // always free your mem
  return 0;
}